home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- CAccordionPane.c
-
- This set of classes implement another method for altering the size and
- location of sub panes when the primary pane is resized.
-
- TCL sub panes are related to the edges of the primary pane. While this
- is quite flexible it does make difficult the need to relate panes as a
- sequence and as a proportion of the whole.
-
- The CAccordionPane classes relates panes as a sequence of vertical or
- horizontal sub-panes. Each pane is either elastic or fixed. When an
- accordion pane is resized each sub-pane is resized so as to keep the order
- and sub-pane proportionality intact. For example, three horizontally
- arranged panes each having 1/3 of the available width can be encoded with
- a CHAccordionPane.
-
- More complex plane arrangements can be had by placing accordion panes
- within accordion panes. Thus, for example, a SmallTalk like browser is no
- more than a CVAccordionPane with two sub-panes. The first sub-pane is a
- CHAccordionPane composed of three CArrayPanes. The second sub-pane is a
- CEditText pane.
-
- To use the accordion panes simply a matter of making it the enclosure of
- the sub-panes. Each time a pane is added as a subpane of another
- AddSubview() is called. AddSubview() is overridden by CVAccordionPane
- and CHAccordionPane to update the proportion tables. If the sub-pane
- is to have a proportion other than make a call to SetSubviewPortion().
-
- NOTE: After all the panes have been added I recommend that you call
- ForceResize() on the top-most accordion pane. This will ensure that the
- sub-panes are sized and located correctlty before they are first drawn.
-
- NOTE: ForceResize() is very slow....
-
- NOTE: The sub-panes are resized as though a call to FitToEnclosure()
- was made. This means than the sub-panes do not share any edges. For my
- current interface needs this is acceptable. However, at some point I plan
- to modify ForceResize() to selectively resize sub-panes either as FitTo-
- Enclosure() or FitToEnclFrame(). The default will remain FitToEnclosure().
-
- Copyright (C) 1993 by Brown University. All rights reserved.
-
- Permission is granted to any individual or institution to use, copy,
- or redistribute the binary version of this software and its
- documentation provided this notice and the copyright notices are
- retained. Permission is granted to any individual or non-profit
- institution to use, copy, modify, or redistribute the source files
- of this software provided this notice and the copyright notices are
- retained. This software may not be distributed for profit, either
- in original form or in derivative works, nor can the source be
- distributed to other than an individual or a non-profit institution.
- Any individual or group interested in seeing and/or using these
- source files but who are prevented from doing so by the above
- constraints should contact Don Wolfe, Vice-President for Computer
- Systems at Brown University, (401) 863-7247, for possible
- software licensing of the source developed at Brown.
-
- Brown University and Andrew James Gilmartin make no representations
- about the suitability of this software for any purpose.
-
- BROWN UNIVERSITY AND ANDREW JAMES GILMARTIN GIVE NO WARRANTY, EITHER
- EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
- INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
- WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
-
- AUTHOR: Andrew_Gilmartin@Brown.Edu
- MODIFIED: 93-03-05
-
- ******************************************************************************/
-
- #include "CAccordionPane.h"
-
-
- #define ACCORDION_DEBUG // DebugStr( (StringPtr) "\p" );
-
-
-
- /******************************************************************************
- IAccordionPane (also defined as IHAccordionPane & IVAccordionPane)
-
- Initialize the accordion pane and its instance variables. NOTE:
- CAccordionPane should not be instanciated directly and thus the need
- for the ASSERT().
- ******************************************************************************/
-
- void CAccordionPane::IAccordionPane
- ( CView *anEnclosure
- , CBureaucrat *aSupervisor
- , short aWidth
- , short aHeight
- , short aHEncl
- , short aVEncl
- , SizingOption aHSizing
- , SizingOption aVSizing )
- {
- ACCORDION_DEBUG
-
- ASSERT( member( this, CHAccordionPane ) || member( this, CVAccordionPane ) );
-
- IPane
- ( anEnclosure
- , aSupervisor
- , aWidth
- , aHeight
- , aHEncl
- , aVEncl
- , aHSizing
- , aVSizing );
-
- itsSubviewPortions = new CRunArray;
- itsSubviewPortions->IRunArray();
-
- itsTotalFixedSize = 0;
-
- } /* IAccordionPane */
-
-
-
- /******************************************************************************
- Dispose
-
- Dispose of the proportion information and then the instance itself.
- ******************************************************************************/
-
- void CAccordionPane::Dispose( void )
- {
- ACCORDION_DEBUG
-
- ForgetObject( itsSubviewPortions );
- inherited::Dispose();
-
- } /* Dispose */
-
-
-
- /******************************************************************************
- ChangeSize
-
- Override the default change size method. This method calls the inherited
- method to change its own size pretending that there are no subviews. Once
- its size has changed all the subviews are changed by ForceResize().
- ******************************************************************************/
-
- void CAccordionPane::ChangeSize( Rect *delta, Boolean redraw )
- {
- CList* theSubviews;
-
- ACCORDION_DEBUG
-
- /* Change my size but not my subviews' size */
-
- theSubviews = itsSubviews;
- itsSubviews = NULL;
- inherited::ChangeSize( delta, redraw );
- itsSubviews = theSubviews;
-
- /* Change the subviews size */
-
- ForceResize( redraw );
-
- } /* ChangeSize */
-
-
-
- /******************************************************************************
- ForceResize
-
- See CVAccordionPane::ForceResize().
- ******************************************************************************/
-
- void CAccordionPane::ForceResize( Boolean redraw )
- {
- ACCORDION_DEBUG
-
- SubclassResponsibility();
-
- } /* ForceResize */
-
-
-
- /******************************************************************************
- SetSubviewPortion
-
- Elastic subviews can be given different proportions of the available
- pane size (width or height). For example, you might want to give the "top"
- pane 1/3 of the space and the "bottom" pane 2/3 of the space. Thus, the
- top plane would have one portion of the space and the bottom pane two
- portions of the space. Call SetSubviewPortion() to assign the proportion.
- By default all panes have equal portions of the space. Note that the space
- given to an elastic pane is based on the sum of all portions minus the
- size of fixed panes. Also note that not all elastic planes with the same
- proportion will have the same size (See ForceResize).
- ******************************************************************************/
-
- void CAccordionPane::SetSubviewPortion
- ( CPane* aSubview
- , short aPortion
- , Boolean redraw )
- {
- long index;
-
- ACCORDION_DEBUG
-
- index = itsSubviews->FindIndex( aSubview );
-
- if ( index > 0 /* && should check that sub is elastic */ )
- {
- itsSubviewPortions->SetValue( index, aPortion );
-
- if ( redraw )
- ForceResize( redraw );
- }
-
- } /* SetSubviewPortion */
-
-
-
- /******************************************************************************
- ForceResize
-
- The panes are distributed down the accordion pane in their subview order.
- Each elastic plane is given its porportion of the height remaining after
- removing the height necessary to accomodate the fixed panes. Since the
- height remaining may not be divisible by the number of portions the extra
- height is proportionally distributed to the elastic panes; thus, not all
- panes with the same proportion of space will have the same height.
- ******************************************************************************/
-
- void CVAccordionPane::ForceResize( Boolean redraw )
- {
- short theTotalSubviews; // the number of subviews
- short theTotalPortions; // the sum of all elastic subview's proportions
- short theTotalWidth; // the width of this pane
- short theTotalHeight; // the height of this pane
- short thePortionSize; // the height of one portion
- short thePortionExtra; // extra height to distribute to portions
- short index; // index into the subview list
- long y; // vertical location of subview
- short theNewHeight; // height of the subview
- short thePortions; // the subview's portion
- CPane* thePane; // the currrent subview
- Rect delta; // how the subview should change size
-
- ACCORDION_DEBUG
-
- /* Do we have any subviews to process */
-
- theTotalSubviews = itsSubviews == NULL ? 0 : itsSubviews->GetNumItems();
- if ( theTotalSubviews == 0 )
- return;
-
- /* How many subview portions do we have? */
-
- theTotalPortions = itsSubviewPortions->SumRange( 1, itsSubviewPortions->GetNumItems() );
-
- /* How many pixels. */
-
- theTotalHeight = this->height;
- theTotalWidth = this->width;
-
- /* How many pixels is given to each portion */
-
- thePortionSize = ( theTotalHeight - itsTotalFixedSize ) / theTotalPortions;
-
- /*
- Because of round off we might have to give each portion some extra pixels.
- How many extra pixels remain
- */
-
- thePortionExtra = ( theTotalHeight - itsTotalFixedSize ) - ( thePortionSize * theTotalPortions );
-
- /* Resize each subview */
-
- /* Constants */
-
- delta.top = 0;
- delta.left = 0;
-
- /* Vertical location of next subview */
-
- y = 0;
-
- for ( index = 1; index <= theTotalSubviews; index++ )
- {
- /* Get subview (we know that they are CPanes) */
-
- thePane = (CPane*) itsSubviews->NthItem( index );
-
- /* What is the subview's new height? */
-
- if ( thePane->vSizing == sizELASTIC )
- {
- /* Distribute its portion of the height */
-
- thePortions = itsSubviewPortions->GetValue( index );
- theNewHeight = thePortionSize * thePortions;
-
- /* Distribute some of the extra height */
-
- if ( thePortionExtra > 0 )
- {
- theNewHeight += Min( thePortions, thePortionExtra );
- thePortionExtra -= thePortions;
- }
- }
- else
- {
- theNewHeight = thePane->height;
- }
-
- /* Place the pane */
-
- thePane->Place( 0, y, FALSE );
-
- /* Change the pane's size */
-
- delta.bottom = theNewHeight - thePane->height;
- delta.right = thePane->hSizing == sizELASTIC ? theTotalWidth - thePane->width : 0;
- thePane->ChangeSize( &delta, redraw );
-
- /* Location for next subview */
-
- y += theNewHeight;
- }
-
- } /* ForceResize */
-
-
-
- /******************************************************************************
- AddSubview
-
- Add the subview to itsSubviews and then update the proportion list. All
- fixed subviews have a portion of zero. The default proportion for elastic
- panes if one.
- ******************************************************************************/
-
- void CVAccordionPane::AddSubview( CView* aSubview )
- {
- CPane* thePane = (CPane*) aSubview;
-
- ACCORDION_DEBUG
-
- /* Subviews have to be CPanes or a subclass */
-
- ASSERT( member( aSubview, CPane ) );
-
- inherited::AddSubview( aSubview );
-
- if ( thePane->vSizing != sizELASTIC )
- {
- itsTotalFixedSize += thePane->height;
- itsSubviewPortions->InsertValue( itsSubviews->GetNumItems(), 0, 1 );
- }
- else
- {
- itsSubviewPortions->InsertValue( itsSubviews->GetNumItems(), 1, 1 );
- }
-
- } /* AddSubview */
-
-
-
- /******************************************************************************
- ForceResize
-
- See comments for CVAccordionPane::ForceResize().
- ******************************************************************************/
-
- void CHAccordionPane::ForceResize( Boolean redraw )
- {
- short theTotalSubviews;
- short theTotalPortions;
- short theTotalWidth;
- short theTotalHeight;
- short thePortionSize;
- short thePortionExtra;
- short index;
- long x;
- short theNewWidth;
- short thePortions;
- CPane* thePane;
- Rect delta;
-
- ACCORDION_DEBUG
-
- /* Do we have any subviews to process */
-
- theTotalSubviews = itsSubviews == NULL ? 0 : itsSubviews->GetNumItems();
- if ( theTotalSubviews == 0 )
- return;
-
- /* How many subview portions do we have? */
-
- theTotalPortions = itsSubviewPortions->SumRange( 1, itsSubviewPortions->GetNumItems() );
-
- /* How many pixels. */
-
- theTotalWidth = this->width;
- theTotalHeight = this->height;
-
- /* How pany pixels if given to each portion */
-
- thePortionSize = ( theTotalWidth - itsTotalFixedSize ) / theTotalPortions;
-
- /*
- Because of round off we might have to give each portion some extra pixels.
- How many extra pixels remain
- */
-
- thePortionExtra = ( theTotalWidth - itsTotalFixedSize ) - ( thePortionSize * theTotalPortions );
-
- /* Resize each subview */
-
- /* Constants */
-
- delta.top = 0;
- delta.left = 0;
-
- /* Horizontal location of next subview */
-
- x = 0;
-
- for ( index = 1; index <= theTotalSubviews; index++ )
- {
- /* Get subview (we know that they are CPanes) */
-
- thePane = (CPane*) itsSubviews->NthItem( index );
-
- /* What is the subview's new height? */
-
- if ( thePane->hSizing == sizELASTIC )
- {
- /* Distribute its portion of the height */
-
- thePortions = itsSubviewPortions->GetValue( index );
- theNewWidth = thePortionSize * thePortions;
-
- /* Distribute some of the extra height */
-
- if ( thePortionExtra > 0 )
- {
- theNewWidth += Min( thePortions, thePortionExtra );
- thePortionExtra -= thePortions;
- }
- }
- else
- {
- theNewWidth = thePane->width;
- }
-
- /* Place the pane */
-
- thePane->Place( x, 0, FALSE );
-
- /* Change the pane's size */
-
- delta.bottom = thePane->vSizing == sizELASTIC ? theTotalHeight - thePane->height: 0;
- delta.right = theNewWidth - thePane->width;
- thePane->ChangeSize( &delta, redraw );
-
- /* Location for next subview */
-
- x += theNewWidth;
- }
-
- } /* ForceResize */
-
-
-
- /******************************************************************************
- AddSubview
-
- See comments for CVAccordionPane::AddSubview().
- ******************************************************************************/
-
- void CHAccordionPane::AddSubview( CView* aSubview )
- {
- CPane* thePane = (CPane*) aSubview;
-
- ACCORDION_DEBUG
-
- ASSERT( member( aSubview, CPane ) );
-
- inherited::AddSubview( aSubview );
-
- if ( thePane->hSizing != sizELASTIC )
- {
- itsTotalFixedSize += thePane->width;
- itsSubviewPortions->InsertValue( itsSubviews->GetNumItems(), 0, 1 );
- }
- else
- {
- itsSubviewPortions->InsertValue( itsSubviews->GetNumItems(), 1, 1 );
- }
-
- } /* AddSubview */
-